﻿namespace Game500.Server

open Microsoft.Xna.Framework
open System.Timers

type ResourceType =
    | PlaneObject = 0
    | SceneObject = 1
    | StaticObject = 2
    | BulletObject = 3
    | DynamicObject = 4

type Shape = Circle of float32 | Polygon of Vector3 * float32 * Vector2 seq

type SceneObject() =
    static let mutable GLOBAL_ID = 10
    let id =
        GLOBAL_ID <- GLOBAL_ID + 1
        GLOBAL_ID
    let mutable rot = 0.0f
    member o.ID = id
    
    member o.SetRotation r = rot <- r
    abstract Position : Vector3
        with get, set
    default o.Position
        with get () = new Vector3()
        and  set _ = ()
    abstract Rotation : float32
        with get, set
    default o.Rotation
        with get () = rot
        and set (r) = rot <- r
    abstract Shape : Shape
        with get, set
    default o.Shape
        with get () = Circle 1.0f
        and set _ = ()

    abstract ResourceID : ResourceType
    default o.ResourceID = ResourceType.SceneObject

    abstract Updated : bool
    default o.Updated = false

    static member Static(pos : Vector3, shape : Shape) =
      { new SceneObject() with
        member o.Position = pos
        member o.ResourceID = ResourceType.StaticObject
        member o.Shape with get () = shape
      }

type DynamicObject(shape : Shape) =
    inherit SceneObject()
    let mutable shape = shape
    let mutable pos = new Vector3()
    let mutable upd = true
    let mutable speed = new Vector3(0.00001f, 0.0f, 0.0f)
    member o.Speed
        with get () = speed
        and  set s = speed <- s
    override o.Position
        with get () = pos
        and  set p =
            pos <- p
            upd <- true
    override o.ResourceID = ResourceType.DynamicObject
    override o.Shape
        with get () = shape
        and set s = shape <- s
    override o.Updated = let u = upd in upd <- false; u

type PlaneObject(start_position : Vector3, start_rotation : float32, start_flipped : bool, shape : Shape) =
    inherit DynamicObject(shape)

    let LIVES = 1
    let mutable next_shot = 0.0f
    let mutable incr_speed = 0.0f
    let mutable flipped = start_flipped
    let mutable health = LIVES
    let mutable frag = 0
    let mutable visible = true

    member o.Explode intr =
        visible <- false
        incr_speed <- 0.0f
        o.Speed <- new Vector3(0.000001f, 0.0f, 0.0f)
        let timer = new Timer(intr * 1000.0)
        timer.AutoReset <- false
        timer.Elapsed.Add (fun _ ->
            o.Position <- start_position
            o.Shape <- shape
            o.SetRotation start_rotation
            flipped <- start_flipped
            health <- LIVES
            visible <- true)
        timer.Enabled <- true
    member o.Hit intr =
        health <- health - 1
        if health > 0 then false else o.Explode intr; true
    member o.Frag
        with get () = frag
        and set f = frag <- f

    member o.Flipped with get () = flipped
    member o.Flip = if o.Position.Y > 10.0f then flipped <- not flipped
    member o.NextShotIn(time) = next_shot <- time
    member o.Tick(t) =
        if next_shot >= 0.0f then next_shot <- next_shot - t
    member o.CanShoot() = next_shot <= 0.0f
    member o.IncrSpeed
        with get() = incr_speed
        and set(d) = incr_speed <- d
    override o.Rotation
        with set r =
                let q = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, r - o.Rotation)
                match o.Shape with
                | Circle _ -> ()
                | Polygon (c, r, ps) -> o.Shape <- Polygon (c, r, Seq.map (fun p -> Vector2.Transform(p, q)) ps)
                let mutable r' = r
                while r' >= MathHelper.TwoPi do r' <- r' - MathHelper.TwoPi
                while r' < 0.0f do r' <- r' + MathHelper.TwoPi
                o.SetRotation r'
    member o.Visible
        with get () = visible
        and set v = visible <- v

    override o.ResourceID = ResourceType.PlaneObject

type Bullet(time : float32, shape : Shape, plane : PlaneObject) =
    inherit DynamicObject(shape)

    let mutable live_time = time
    member o.Tick(t) = live_time <- live_time - t
    member o.Dead() = live_time <= 0.0f
    member o.Kill() = live_time <- 0.0f
    member o.Plane with get () = plane

    override o.ResourceID = ResourceType.BulletObject
